﻿using LuaFramework;
using LuaInterface;
using System.Collections;
using UnityEngine;

public class LuaComponent : MonoBehaviour
{
    //Lua表
    public LuaTable table = null;

    //[NoToLua]
    //public string luaClassName;
    private string luaClassName;

    //添加LUA组件
    public static LuaTable Add(GameObject go, LuaTable tableClass)
    {
        LuaFunction fun = tableClass.GetLuaFunction("New");
        if (fun == null)
        {
            Debug.LogErrorFormat("对象{0}的LuaComponent没定义New！", go.name);
            return null;
        }
        LuaTable ret = fun.Invoke<LuaTable, LuaTable>(tableClass);
        fun.Dispose();
        LuaComponent cmp = go.AddComponent<LuaComponent>();
        cmp.table = ret;
        cmp.InitTable();
        /** 对象激活状态，Awake、OnEnable消息执行时cmp.table为空，没有调用Lua的方法，这里手动补上
         *  对象非激活状态，Awake、OnEnable消息会延迟到激活时执行，cmp.table已经赋值，无需再额外调用cmp.Awake和cmp.OnEnable
         */
        if (go.activeInHierarchy)
        {
            cmp.Awake();
            cmp.OnEnable();
        }
        return cmp.table;
    }

    //获取lua组件
    public static LuaTable Get(GameObject go, LuaTable table)
    {
        LuaComponent[] cmps = go.GetComponents<LuaComponent>();
        foreach (LuaComponent cmp in cmps)
        {
            string mat1 = table.ToString();
            string mat2 = cmp.table.GetMetaTable().ToString();
            //string mat2 = cmp.table["class"].ToString();
            if (mat1 == mat2)
            {
                return cmp.table;
            }
        }
        return null;
    }

    public static LuaTable GetComponentInChildren(GameObject go, LuaTable table)
    {
        LuaComponent[] cmps = go.GetComponentsInChildren<LuaComponent>();
        foreach (LuaComponent cmp in cmps)
        {
            string mat1 = table.ToString();
            string mat2 = cmp.table.GetMetaTable().ToString();
            //string mat2 = cmp.table["class"].ToString();
            if (mat1 == mat2)
            {
                return cmp.table;
            }
        }
        return null;
    }

    public static LuaTable GetOrAdd(GameObject go, LuaTable table)
    {
        LuaTable resultTable = Get(go, table);
        if (resultTable != null)
        {
            return resultTable;
        }
        return Add(go, table);
    }

    public static void Remove(GameObject go, LuaTable table)
    {
        LuaComponent[] cmps = go.GetComponents<LuaComponent>();
        foreach (LuaComponent cmp in cmps)
        {
            string mat1 = table.ToString();
            if (cmp.table == null)
            {
                continue;
            }
            string mat2 = cmp.table.GetMetaTable().ToString();
            //string mat2 = cmp.table["class"].ToString();
            if (mat1 == mat2)
            {
                Object.Destroy(cmp);
                break;
            }
        }
    }

    protected void InitTable()
    {
        table["gameObject"] = this.gameObject;
        table["transform"] = this.transform;
    }

    protected virtual LuaTable SetTableClass()
    {
        var tableClass = LuaManager.Instance.Lua[luaClassName] as LuaTable;
        if (tableClass == null)
        {
            Debug.LogErrorFormat("找不到Lua Table：{0}", luaClassName);
            return null;
        }

        LuaFunction fun = tableClass.GetLuaFunction("New");
        if (fun == null)
        {
            Debug.LogErrorFormat("找不到方法：{0}.New", luaClassName);
            return null;
        }
        LuaTable ret = fun.Invoke<LuaTable, LuaTable>(tableClass);
        fun.Dispose();

        tableClass.Dispose();

        this.table = ret;
        this.InitTable();
        return this.table;
    }

    void Awake()
    {
        if (!string.IsNullOrEmpty(luaClassName))
        {
            SetTableClass();
        }

        CallLuaFunction("Awake", table);
    }

    void OnEnable()
    {
        CallLuaFunction("OnEnable", table);
    }

    void OnDisable()
    {
        CallLuaFunction("OnDisable", table);
    }

    void Start()
    {
        CallLuaFunction("Start", table);
    }

    void Update()
    {
        //效率问题有待测试和优化
        //可在lua中调用UpdateBeat替代
        //CallLuaFunction("Update", table);
        LuaFunction fun = table.GetLuaFunction("Update");
        if (fun != null)
        {
            fun.Call(table, gameObject);
        }
    }

    void OnAnimationEvent(AnimationEvent e)
    {
        CallLuaFunction("OnAnimationEvent", table, e);
    }

    //PoolManager Message
    void OnSpawn()
    {
        CallLuaFunction("OnSpawn", table);
    }

    //PoolManager Message
    void OnDespawn()
    {
        CallLuaFunction("OnDespawn", table);
    }

    void OnCollisionEnter(Collision collision)
    {
        CallLuaFunction("OnCollisionEnter", table, collision);
    }

    void OnCollisionExit(Collision collision)
    {
        CallLuaFunction("OnCollisionExit", table, collision);
    }

    void OnApplicationFocus(bool focus)
    {
        CallLuaFunction("OnApplicationFocus", table, focus);
    }

    void OnApplicationPause(bool pause)
    {
        CallLuaFunction("OnApplicationPause", table, pause);
    }

    private void OnApplicationQuit()
    {
        CallLuaFunction("OnApplicationQuit", table);
    }

    void OnDestroy()
    {
        CallLuaFunction("OnDestroy", table);

        if (table != null)
        {
            table.Dispose();
            table = null;
        }
    }

    void CallLuaFunction(string funcName, LuaTable t)
    {
        if (t == null)
        {
            return;
        }

        LuaFunction func = table.GetLuaFunction(funcName);
        if (func != null)
        {
            func.Call(t);
            func.Dispose();
        }
    }

    void CallLuaFunction(string funcName, LuaTable t, AnimationEvent e)
    {
        if (t == null)
        {
            return;
        }

        LuaFunction func = table.GetLuaFunction(funcName);
        if (func != null)
        {
            func.Call(t, e);
            func.Dispose();
        }
    }

    void CallLuaFunction(string funcName, LuaTable t, Collision c)
    {
        if (t == null)
        {
            return;
        }

        LuaFunction func = table.GetLuaFunction(funcName);
        if (func != null)
        {
            func.Call(t, c);
            func.Dispose();
        }
    }

    void CallLuaFunction(string funcName, LuaTable t, bool b)
    {
        if (t == null)
        {
            return;
        }

        LuaFunction func = table.GetLuaFunction(funcName);
        if (func != null)
        {
            func.Call(t, b);
            func.Dispose();
        }
    }

    public void CallLuaFunction(string funcName)
    {
        LuaFunction func = table.GetLuaFunction(funcName);
        if (func != null)
        {
            func.Call(table);
            func.Dispose();
        }
    }
}